import { IArrayList } from './types'
import { IIterator } from '@/sources/types'

/**
 * 动态数组
 */
class ArrayList<T = number> implements IArrayList<T> {
    // 数组内元素的数量
    public sizes: number = 0
    // 默认的容量
    public DEFAULT_CAPICITY: number = 10
    // 数组
    public arr: Array<T | undefined>

    constructor(capicity: number = 10) {
        if (capicity <= 0) throw new Error('容量必须大于0')
        // 容量和默认的容量不相同
        if (capicity !== this.DEFAULT_CAPICITY) {
            this.DEFAULT_CAPICITY = capicity;
        }
        // 初始化数组 并且覆盖初始容量
        this.arr = new Array(this.DEFAULT_CAPICITY)
    } 
    /**
     * 查看array
     */
    get array() {
        return this.arr! as Array<T>;
    }

    /**
     * 修改array
     */
    createArray(newArr: Array<T>) {
        // 批量创建新的元素
        newArr.forEach(ele => {
            this.add(ele)
        })
    }

    get capicity() {
        return this.arr.length;
    }

    /**
     * sizes--
     */
    descSize() {
        this.sizes--
    }

    /**
     * 获取数组的容量
     */
    size() {
        return this.sizes;
    }

    /**
     * 数组是否为空
     */
    isEmpty() {
        return this.sizes === 0
    }

    /**
     * 是否包含元素element
     * @param element 
     */
    contains(element: T) {
        return this.indexOf(element) !== -1
    }

    /**
     * 添加元素
     * @param element 
     */
    add(element: T) {
        // 检查元素的合法性
        this.checkElement(element);

        // 检查数组是否需要扩容
        this.ensureCapicity()

        // 添加元素 同时sizes加1
        this.arr[this.sizes++] = element;
        return this.sizes;
    }

    /**
     * 取出最后一个元素
     */
    pop() {
        return this.remove(this.sizes - 1)
    }

    /**
     * 往头部添加元素
     * @param element 
     */
    unshift(element: T) {
        this.addToIndex(0, element);
        return this.sizes
    }

    /**
     * 取出头部元素
     */
    shift() {
        return this.remove(0);
    }


    /**
     * 修改索引index处的元素
     * @param index 
     * @param element 
     */
    set(index: number, element: T) {
        // 检验参数
        this.checkIndex(index, true);
        this.checkElement(element);
        // 新旧是否相同
        if (this.arr[index] === element) return;
        // 新旧元素不相同 
        this.arr[index] = element
    }

    /**
     * 往index索引处添加元素
     * @param index 
     * @param element 
     */
    addToIndex(index: number, element: T) {
        // 检验参数合法性
        this.checkIndex(index);
        this.checkElement(element);

        let sizes = this.sizes;
        // 校验容量
        this.ensureCapicity();

        this.sizes++;
        // 往数组的最后添加元素
        if (index === sizes) {
            // 直接添加
            this.arr[index] = element;
            return;
        }

        let i = sizes - 1;
        // 移动元素
        for (; i >= index; i--) {
            this.arr[i + 1] = this.arr[i]
        }
        // 添加元素
        // debugger
        this.arr[index] = element;
    }

    /**
     * 获取索引处的元素
     * @param index 
     */
    get(index: number) {
        this.checkIndex(index);
        return this.arr[index]!;
    }

    /**
     * 删除index索引处的元素
     * @param index 
     */
    remove(index: number) {
        // 校验索引的合法性
        this.checkIndex(index, true);
        const oldEle = this.arr[index];
        // 保存旧的sizes
        const sizes = this.sizes;

        // 移动元素
        let i = index,
            arr = this.arr;

        // 往前移动元素    
        for (; i < sizes - 1; i++) {
            arr[i] = arr[i + 1]
        }

        // 处理最后一个元素
        arr[sizes - 1] = undefined;
        this.sizes--;

        return oldEle!
    }

    /**
     * 从头开始检索元素的索引
     * @param element 
     */
    indexOf(element: T) {
        // 检验参数的合法性
        this.checkElement(element);
        let i = 0,
            arr = this.arr;
        for (; i < this.sizes; i++) {
            if (arr[i] === element) return i;
        }

        // 找不到, 返回-1
        return -1
    }

    /**
     * 从尾开始检索元素的索引
     * @param element 
     */
    lastIndexOf(element: T) {
        // 检验参数
        this.checkElement(element);
        let i = this.sizes,
            arr = this.arr;

        for (; i >= 0; i--) {
            if (arr[i] === element) return i;
        }

        // 找不到元素
        return -1
    }


    /**
     * 清空元素
     */
    clear() {
        // 清空数组
        this.sizes = 0;
        this.arr.length = 0;
    }

    /**
     * 遍历数组
     * @param cb 
     */
    forEach(cb: IIterator<T>) {
        let i = 0,
            arr = this.arr,
            sizes = this.sizes;
        for (; i < sizes; i++) {
            cb(arr[i]!, i)
        }
    }

    /**
     * 交换两个索引的值
     * @param i 
     * @param j 
     */
    swap(i: number, j: number) {
        this.checkIndex(i, true)
        this.checkIndex(j, true)

        const tem = this.arr[i] 
        this.arr[i] = this.arr[j]
        this.arr[j] = tem
    }

    /**
     * 检查索引是否越界
     * @param index 
     * @param includeBoundary 是否包含边界
     */
    private checkIndex(index: number, includeBoundary?: boolean) {
        if ((index < 0 || index > this.sizes) || (includeBoundary && index === this.sizes)) {
            console.log(index, includeBoundary, this.sizes)
            throw new Error("索引越界了~~")
        }
    }

    /**
     * 检查元素的合法性
     * @param element 
     */
    private checkElement(element: T) {
        if (element == null) {
            throw new Error('元素不合法~~~')
        }
    }

    /**
     * 检验数组容量
     */
    private ensureCapicity() {
        // 检查数组是否需要扩容
        if (this.sizes >= this.arr.length) {
            this.enlargeCapicity();
        }
    }


    /**
     * 扩容
     */
    private enlargeCapicity() {
        // 扩容两倍
        const newCapicity = this.DEFAULT_CAPICITY << 1;
        // 创建新数组
        const newArr = new Array<T>(newCapicity)

        // 将老的数组移动到新的数组中
        const oldArr = this.arr,
            sizes = this.sizes;
        let i = 0;
        for (; i < sizes; i++) {
            newArr[i] = oldArr[i]!
        }

        // 更新数组
        this.arr = newArr;
    }
}


export default ArrayList